using System;
using System.Collections.Generic;
using System.Text;
using DCRF.Common.Collection;
using DCRF.Common.Helper;
using DCRF.Common.Primitive;
using System.Threading;
using System.Collections;
using DCRF.Common.Interface;
using DCRF.Common.DBC;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using DCRF.Common.Definition;
using DCRF.Common.Connection;
using DCRF.Common.Attributes;
using NetSockets.Peer;
using DCRF.Common.Support;

namespace DCRF.Common.Core
{
    public class BlockWeb : IContainerBlockWeb
    {
        #region private fields

        private static Random random = new Random();  //used to create random id for web
        private Dictionary<Guid, IContainedBlock> innerBlocks = new Dictionary<Guid, IContainedBlock>();

        /// <summary>
        /// BlockWeb does not load/dispose Blocks. It's brokers job.
        /// </summary>
        private IBlockBroker blockBroker = null;
        private IContainerBlock containerBlock = null;  //the block that has hosted this web, we refer to this if cannot find something

        /// <summary>
        /// A unique ID to be used as PeerID when connecting multiple BlockWebs to each-other
        /// </summary>
        private string myId = null;
        private PlatformType platform = PlatformType.Neutral;

        //private Dictionary<Guid, IBlock> blockAccessors = new Dictionary<Guid, IBlockAccessor>();
        private Dictionary<string, Connector> globalConnectors = new Dictionary<string, Connector>();

        private Dictionary<string, IBlockWeb> peers = new Dictionary<string, IBlockWeb>();
      
        #endregion

        public event PeerConnectDelegate PeerConnected;
        public event PeerConnectDelegate PeerDisconnected;

        #region Public Properties

        public string Id
        {
            get
            {
                return myId;
            }
        }

        public int BlockCount
        {
            get
            {

                return innerBlocks.Count;
            }
        }

        //public PlatformType Platform
        //{
        //    get
        //    {
        //        return platform;
        //    }
        //}

        public string Address
        {
            get
            {
                if (peerManager == null) return "";
                return peerManager.Address;
            }
        }

        public string Host
        {
            get
            {
                if (peerManager == null) return "";
                return peerManager.Host;
            }
        }

        public int Port
        {
            get
            {
                if (peerManager == null) return -1;
                return peerManager.Port;
            }
        }

        public IList<Guid> BlockHandles
        {
            get
            {
                return new List<Guid>((IEnumerable<Guid>)innerBlocks.Keys);
            }
        }

        public IGlobalConnector this[string key]
        {
            get
            {
                if (globalConnectors.ContainsKey(key))
                {
                    return globalConnectors[key];
                }

                foreach (string peerId in peers.Keys)
                {
                    object keys = peers[peerId].GetBlockWebMetaInfo(BlockWebMetaInfoType.GlobalConnectorKeys, null);

                    if ( keys != null && (keys as List<string>).Contains(key) )
                    {
                        return peers[peerId][key];
                    }
                }

                //for blockweb, container of globalConnector is me myself, 
                //so prevent infinite loop in connectorCollection looking for container connector if 
                //key does not exist
                //logEvent(LogType.Connector, "Creating Connector: " + key);

                globalConnectors.Add(key, new Connector(key, this, true));

                return globalConnectors[key];
            }
        }

        public object GetBlockWebMetaInfo(BlockWebMetaInfoType type, string itemName)
        {
            switch (type)
            {
                case BlockWebMetaInfoType.GlobalConnectorKeys: return new List<string>((IEnumerable<string>)globalConnectors.Keys);
                case BlockWebMetaInfoType.GlobalConnectorEndpoints: return globalConnectors[itemName].GetEndPointsDescription();
                case BlockWebMetaInfoType.PeersInfo:
                    {
                        Dictionary<string, string> result = new Dictionary<string, string>();

                        foreach (string item in peers.Keys)
                        {
                            result.Add(item, peers[item].Address);
                        }

                        return result;
                    }
                //case BlockWebMetaInfoType.BlockCount: return innerBlocks.Count;
                //case BlockWebMetaInfoType.BlockHandles: return new List<Guid>((IEnumerable<Guid>)innerBlocks.Keys);
                case BlockWebMetaInfoType.Platform: return platform;
            }

            return null;
        }

        //public List<string> GlobalConnectorKeys
        //{
        //    get
        //    {
        //        return 
        //    }
        //}

        //public List<string> GetGlobalConnectorEndpoints(string connectorKey)
        //{
            
        //}

        //public List<object> ProcessGlobalConnectorRequest(string connectorKey, params object[] args)
        //{
        //    //if there is no such connector, return null
        //    List<object> result = new List<object>();

        //    if (globalConnectors.ContainsKey(connectorKey))
        //    {
        //        result = globalConnectors[connectorKey].ProcessRequestAll(args);
        //    }

        //    if (containerBlock != null)
        //    {
        //        List<object> parentResult = containerBlock.ProcessLocalConnector(connectorKey, args);

        //        if (parentResult.Count > 0)
        //        {
        //            result.AddRange(parentResult);
        //        }
        //    }

        //    return result;           
        //}
       

        #endregion

        #region Constructor

        private void construct(string id, IBlockBroker broker, PlatformType platform, IContainerBlock cont)
        {
            this.platform = platform;

            if (broker != null)
            {
                blockBroker = broker;
            }

            if (id != null)
            {
                this.myId = id;
            }
            else
            {
                this.myId = random.Next().ToString();
            }

            containerBlock = cont;

            startServer();
        }

        public BlockWeb()
        {
            construct(null, null, PlatformType.Neutral, null);
        }

        public BlockWeb(string id)
        {
            construct(id, null, PlatformType.Neutral, null);
        }

        public BlockWeb(string id, IBlockBroker broker)
        {
            construct(id, broker, PlatformType.Neutral, null);
        }

        public BlockWeb(string id, IBlockBroker broker, PlatformType platform)
        {
            construct(id, broker, platform, null);
        }

        public BlockWeb(string id, IBlockBroker broker, PlatformType platform, IContainerBlock containerBlock)
        {
            construct(id, broker, platform, containerBlock);
        }

        public BlockWeb(string id, BlockWeb parent, IContainerBlock containerBlock)
        {
            PlatformType parentPlatform = (PlatformType)parent.GetBlockWebMetaInfo(BlockWebMetaInfoType.Platform, null);
            construct(id, parent.blockBroker , parentPlatform, containerBlock);
        }

        #endregion

        #region Block Add/Delete

        /// <summary>
        /// Loads a block and adds it to the runtime blocks. CID is block definition and result Guid is a handle 
        /// to point to the runtime instance of the block.
        /// </summary>
        /// <param name="id">contains basic info (id, ver, prod) used to load the Block</param>
        /// input handle just</param>
        /// <returns>A handle to newly instantiated block</returns>
        /// 
        public virtual Guid AddBlock(CID id)
        {
            return addBlock(id, Guid.Empty);
        }

        protected virtual Guid addBlock(CID handle, Guid predefinedId)
        {
            IContainedBlock comp = null;

            Guid guid = predefinedId;

            if (guid.Equals(Guid.Empty))
            {
                guid = Guid.NewGuid();
            }

            List<Guid> myBlocks = FindBlocks(handle);

            if (myBlocks.Count > 0)
            {
                //here we have a list of multiple instances of this Block
                //we should select one of them here!
                IContainedBlock block = innerBlocks[myBlocks[0]];

                //if it is single instance then it has only one
                //TODO: update code according to new attributes
                //if (block.BlockInfo.Type == BlockType.SingleInstance)
                //{
                //    logEvent("AddBlock: Returning single-instance block " + handle.ToString() + " with ID = " + guid.ToString());
                //    return block.Id;
                //}

                //if it is multi-instance we add a new instance
            }

            logEvent(LogType.AddBlock, "Adding - Block: " + handle.ToString() + " with ID = " + guid.ToString());

            //if (globalConnectors.ContainsKey(EventCode.AddingBlock))
            //{
            //    bool cancelOperation = false;

            //    logEvent(EventCode.AddingBlock,this, handle, new ValueTypeHolder<bool>(ref cancelOperation));

            //    if (cancelOperation)
            //    {
            //        return Guid.Empty;
            //    }
            //}

            if (blockBroker != null)
            {
                comp = blockBroker.LoadBlock(handle, guid, this);
            }

            logEvent(LogType.AddBlock, "Load done - Block: " + handle.ToString() + " with ID = " + guid.ToString());

            //EW lookup

            if (comp == null)
            {
                throw new System.Exception("Could not load the given handle");
            }

            //TODO: add code to read platform from attributes of the block
            //if (Platform != PlatformType.Neutral && comp.BlockInfo.Platform != PlatformType.Neutral)
            //{
            //    if (Platform != comp.BlockInfo.Platform)
            //    {
            //        throw new System.Exception("Cannot add a Block from an incompatible paltform");
            //    }
            //}

            if (globalConnectors.ContainsKey(EventCode.BlockLoaded))
            {
                //TODO: replace by a call to processglobal...
                //globalConnectors[EventCode.BlockLoaded].Raise(this, guid);
            }

            initBlock(comp);

            logEvent(LogType.AddBlock, "Init Done - Block: " + handle.ToString() + " with ID = " + guid.ToString());

            if (globalConnectors.ContainsKey(EventCode.BlockAdded))
            {
                //TODO: replace by a call to processglobal... (no need for above if)
                //globalConnectors[EventCode.BlockAdded].Raise(this, guid);
            }

            return guid;
        }

        /// <summary>
        /// here we initialize the newly created Block and route it throught the default event pipeline
        /// </summary>
        /// <param name="comp"></param>
        protected virtual void initBlock(IContainedBlock comp)
        {
            Check.Ensure(comp != null);

            innerBlocks.Add(comp.Id, comp);

            try
            {
                //perform initialization steps
                comp.InitBlock();
            }
            catch (System.Exception exc)
            {
                bool throwException = true;

                if (globalConnectors.ContainsKey(EventCode.ExceptionOccured))
                {
                    try
                    {
                        //TODO: replace with a call to ProcessGlobval...
                        //globalConnectors[EventCode.ExceptionOccured].Raise(exc, new ValueTypeHolder<bool>(ref throwException));
                    }
                    catch
                    {
                        //if an exception handler throws an exception then there's really
                        //something bad happening
                        throw exc;
                    }
                }

                if (throwException) throw exc;
            }
        }

        public virtual void DeleteBlock(Guid handle)
        {
            logEvent(LogType.DeleteBlock, "DeleteBlock Begin - Handle: " + handle.ToString());

            IContainedBlock comp = innerBlocks[handle];

            if (globalConnectors.ContainsKey(EventCode.DeletingBlock))
            {
                //TODO: replace with call to processglobal...
                //bool cancelOperation = false;

                //globalConnectors[EventCode.DeletingBlock].Raise(this, handle, new ValueTypeHolder<bool>(ref cancelOperation));

                //if (cancelOperation)
                //{
                //    return;
                //}
            }

            comp.Dispose();
            innerBlocks.Remove(handle);
            //comp.BlockWeb = null;
            //blockAccessors.Remove(handle);

            if (globalConnectors.ContainsKey(EventCode.BlockDeleted))
            {
                //TODO: replace with a call to processglobal...
                //globalConnectors[EventCode.BlockDeleted].Raise(this, handle);
            }

            blockBroker.DisposeBlock(comp);

            logEvent(LogType.DeleteBlock, "DeleteBlock Done - Handle: " + handle.ToString());
        }

        #endregion

        #region Block Search

        public List<Guid> FindBlocks(CID handle)
        {
            List<Guid> result = new List<Guid>();

            //TODO: rewrite according to new attributes
            //foreach (Guid key in innerBlocks.Keys)
            //{
            //    if (innerBlocks[key].BlockInfo.BlockID.Equals(handle))
            //    {
            //        result.Add(key);
            //    }
            //}

            return result;
        }
       
        /// <summary>
        /// We send out IBlocks to the outer world.
        /// </summary>
        /// <param name="handle"></param>
        /// <returns></returns>
        public IBlock this[Guid handle]
        {
            get
            {
                //1st priority: check internal blocks
                if (innerBlocks.ContainsKey(handle))
                {
                    return innerBlocks[handle];
                }

                //2nd priority: check container's web if it has a block with this handle
                if (containerBlock != null)
                {
                    IBlock externalBlock = containerBlock.GetParentWebBlock(handle);

                    if ( externalBlock != null )
                    {
                        return externalBlock;
                    }
                }

                //3rd priority: check peers
                foreach (string peerId in peers.Keys)
                {
                    if ( peers[peerId].BlockHandles.Contains(handle) )
                    {
                        return peers[peerId][handle];
                    }
                }

                return null;
            }
        }

        /// <summary>
        /// comma separated list of tags - returns list of blocks that have ALL of these tags
        /// </summary>
        /// <param name="lookupTags"></param>
        /// <returns></returns>
        public List<Guid> FindBlocks(string lookupTag)
        {
            List<Guid> result = new List<Guid>();

            foreach (IContainedBlock block in innerBlocks.Values)
            {
                //TODO: update according to new attributes
                //if (block.BlockInfo.Tags.Contains(lookupTag))
                //{
                //    result.Add(block.Id);
                //}
            }

            //EW lookup


            return result;
        }

        public void ReloadBlocks()
        {
            //first clear broker cache
            blockBroker.ClearCache();

            Guid[] blockKeys = new Guid[innerBlocks.Count];
            innerBlocks.Keys.CopyTo(blockKeys, 0);

            //reload all blocks
            foreach (Guid id in blockKeys)
            {
                CID cid = GetBlockId(id);

                IContainedBlock currentBlock = innerBlocks[id];
                bool cancelOperation = false;

                object blockState = currentBlock.OnBeforeReload(ref cancelOperation);

                if (!cancelOperation)
                {
                    currentBlock.Dispose();
                    IContainedBlock newBlock = blockBroker.LoadBlock(cid, id, this);
                    newBlock.OnAfterReload(blockState);

                    innerBlocks[id] = newBlock;
                }
            }

        }

        #endregion

        #region Distribution Support
        private PeerManager peerManager = null;

        private void startServer()
        {
            peerManager = new PeerManager(this.myId, new PeerLogDelegate(intLogEvent));

            peerManager.SetHandler(MsgCode.CallBlockWebMethod, new MessageHandlerDelegate(onCallWebMethodRequest));
            peerManager.SetHandler(MsgCode.CallBlockMethod, new MessageHandlerDelegate(onCallBlockMethodRequest));
            peerManager.SetHandler(MsgCode.CallConnectorMethod, new MessageHandlerDelegate(onCallConnectorMethodRequest));

            peerManager.PeerDisconnected += new PeerConnectDelegate(peerManager_PeerDisconnected);
            peerManager.PeerConnected += new PeerConnectDelegate(peerManager_PeerDisconnected);
        }

        void peerManager_PeerDisconnected(string peerId, bool isConnected, string peerHost, int peerPort)
        {
            logEvent(LogType.PeerConnection, "Peer " + peerId + " " + (isConnected ? "connected" : "disconnected"));

            if (isConnected == false)
            {
                if (peers.ContainsKey(peerId)) peers.Remove(peerId);

                if (PeerDisconnected != null) PeerDisconnected(peerId, isConnected, peerHost, peerPort);
            }
            else
            {
                if (!peers.ContainsKey(peerId))
                {
                    peers.Add(peerId, new ProxyBlockWeb(peerId, peerHost, peerPort, peerManager));
                }

                if (PeerConnected != null) PeerConnected(peerId, isConnected, peerHost, peerPort);
            }
        }

        public bool Connect(string host, int port, string peerId)
        {
            if (!peerManager.HasPeer(peerId))
            {
                logEvent(LogType.PeerConnection, "Connecting to " + peerId + " at " + host + ":"+port.ToString());

                bool connected = peerManager.Connect(host, port, peerId);

                if (connected)
                {
                    peers.Add(peerId, new ProxyBlockWeb(peerId, host, port, peerManager));
                }

                return connected;
            }

            return true;
        }

        public bool Connect(IBlockWeb web, string peerId)
        {
            if (web.Id != peerId) return false;

            peers.Add(peerId, web);

            //also inform other peer
            web.Connect(this, Id);

            return true;
        }

        public IBlockWeb GetPeer(string peerId)
        {
            return peers[peerId];
        }

        //private void syncMyBlocks(string peerId)
        //{
        //    if (peerId != null)
        //    {
        //        peerManager.SendMessageAsync(peerId, MsgCode.SyncBlocks, BlockHandles);
        //    }
        //    else
        //    {
        //        peerManager.BroadcastMessageAsync(MsgCode.SyncBlocks, BlockHandles);
        //    }
        //}

        //private void onSyncBlocks(PeerSocket sender, string msgCode, Guid msgId, string senderId, string receiverId, List<object> data)
        //{
        //    IList<Guid> blocks = data[0] as IList<Guid>;

        //    if (!peerBlocks.ContainsKey(senderId))
        //    {
        //        peerBlocks.Add(senderId, new List<Guid>());
        //    }

        //    peerBlocks[senderId].Clear();
        //    peerBlocks[senderId].AddRange(blocks);
        //}

        public void Disconnect(string peerId)
        {
            logEvent(LogType.PeerConnection, "Disconnecting from " + peerId);

            peerManager.Disconnect(peerId);
            peers.Remove(peerId);
        }

        //TODO: there is a copy of this in simpleBlockBroker and runtime, merge them in a single place
        public CID GetBlockId(Guid id)
        {
            IContainedBlock block = innerBlocks[id];
            object[] result = block.GetType().GetCustomAttributes(typeof(BlockIdAttribute), true);

            if (result.Length == 1)
            {
                return (result[0] as BlockIdAttribute).BlockId;
            }

            throw new System.Exception("BlockId has problem");
        }

        public bool MigrateBlock(Guid guid, string peerId)
        {
            logEvent(LogType.MigrateBlock, "MigrateBlock Begin - ID = "+guid.ToString()+ " to "+peerId);

            bool cancelOperation = false;
            IContainedBlock comp = innerBlocks[guid];
            CID blockId = GetBlockId(guid);
            object customData = comp.OnBeforeMigration(ref cancelOperation);

            //the block does not support migration
            if (cancelOperation) return false;

            //we do not send startupArgs when migrating.We suppose that it is reflected in the properties of the block
            List<object> response = peerManager.SendMessage(peerId, MsgCode.CallBlockWebMethod, "MigrateBlock", guid, blockId, customData);

            if (response == null || response.Count ==0) return false;

            //if response contains guid of this block, means success
            if (response[0].Equals(guid))
            {
                this.DeleteBlock(guid);

                //just to make sure block is deleted (in DeleteBlock onBeforeDelte can cancel oepration)
                if ( innerBlocks.ContainsKey(guid) )
                {
                    innerBlocks.Remove(guid);
                }

                //blockAccessors.Remove(guid);
                logEvent(LogType.MigrateBlock, "MigrateBlock Done OK - ID = " + guid.ToString() + " to " + peerId);

                return true;
            }

            logEvent(LogType.MigrateBlock, "MigrateBlock Done Fail - ID = " + guid.ToString() + " to " + peerId);

            return false;
        }


        private void onCallConnectorMethodRequest(PeerSocket sender, string msgCode, Guid msgId, string senderId, string receiverId, List<object> data)
        {            
            object result = null;
            Guid blockId = (Guid)data[0];
            string connectorKey = data[1].ToString();
            string methodName = data[2].ToString();

            logEvent(LogType.PeerRequest, "Peer " + senderId + " sent request: " + msgCode);
            logEvent(LogType.Connector, "onCallConnectorMethodRequest");

            //others are arguments
            switch (methodName)
            {
                case "AttachEndPointG":  //AttachEndPoint (Guid)
                {
                    object[] args = (object[])data[3];
                    Guid cid = (Guid)args[0];
                    string service = (string)args[1];
                    object[] predefinedValues = args[2] as object[];

                    if (blockId == Guid.Empty)
                    {
                        result = this[connectorKey].AttachEndPoint(cid, service, predefinedValues);                         
                    }
                    else
                    {
                        result = this[blockId][connectorKey].AttachEndPoint(cid, service, predefinedValues);
                    }

                    break;
                }
                case "AttachEndPointV":  //AttachEndPoint (object Value)
                {
                    object[] args = (object[])data[3];
                    object value = args[0];

                    if (blockId == Guid.Empty)
                    {
                        result = this[connectorKey].AttachEndPoint(value);
                    }
                    else
                    {
                        result = this[blockId][connectorKey].AttachEndPoint(value);                        
                    }

                    break;
                }
                case "DetachEndPoint":
                {
                    string key = ((object[])data[3])[0].ToString();
                    if (blockId == Guid.Empty)
                    {
                        this[connectorKey].DetachEndPoint(key);
                    }
                    else
                    {
                        this[blockId][connectorKey].DetachEndPoint(key);
                    }

                    break;
                }
                case "ProcessRequestAll":
                {
                    object[] args = ((object[])data[3]);
                    if (blockId == Guid.Empty)
                    {
                        result = this[connectorKey].ProcessRequestAll(args);
                    }
                    else
                    {
                        throw new System.Exception("You cannot call a block's local connector");
                    }

                    break;
                }
                case "ChainEndPoint":
                {
                    object[] args = (object[])data[3];
                    Guid bhandle = (Guid)args[0];
                    string chainConnectorKey = (string)args[1];

                    if (blockId == Guid.Empty)
                    {
                        result = this[connectorKey].ChainEndPoint(bhandle, chainConnectorKey);
                    }
                    else
                    {
                        result = this[blockId][connectorKey].ChainEndPoint(bhandle, chainConnectorKey);
                    }

                    break;
                }
            }

            sender.SendMessageAsync(msgCode, msgId, result);
        }


        private void onCallBlockMethodRequest(PeerSocket sender, string msgCode, Guid msgId, string senderId, string receiverId, List<object> data)
        {            
            object result = null;
            Guid blockId = (Guid)data[0];
            string methodName = data[1].ToString();
            string serviceName = "";
            //object[] args = (object[])data[2];

            CID info = GetBlockId(blockId);

            logEvent(LogType.PeerRequest, "Peer " + senderId + " sent request: " + msgCode);
            logEvent(LogType.ProcessRequest, "onCallBlockMethodRequest - Name = " + methodName + " ID=" + info.ToString());

            try
            {
                //others are arguments
                switch (methodName)
                {
                    case "ProcessRequest":
                        {
                            serviceName = data[2].ToString();
                            object[] args = (object[])data[3];

                            logEvent(LogType.ProcessRequest, "onCallBlockMethodRequest - Name = " + methodName + " ID=" + info.ToString() + " service=" + serviceName);

                            result = this[blockId].ProcessRequest(serviceName, args);

                            break;
                        }
                }
            }
            catch (System.Exception exc)
            {
                logEvent(LogType.Exception,"Error Handling Call on Block Service (" + methodName + ","+serviceName+"): " + exc.Message);
                throw;
            }

            sender.SendMessageAsync(msgCode, msgId, result);
        }

        private void onCallWebMethodRequest(PeerSocket sender, string msgCode, Guid msgId, string senderId, string receiverId, List<object> data)
        {            
            object result = null;
            string methodName = data[0].ToString();

            logEvent(LogType.PeerRequest, "Peer " + senderId + " sent request: " + msgCode);
            logEvent(LogType.BlockWeb, "onCallMethodRequest - Name = " + methodName);

            try
            {
                //others are arguments
                switch (methodName)
                {
                    case "AddBlock": result = AddBlock((CID)data[1]); break;
                    case "GetBlockId": result = GetBlockId((Guid)data[1]); break;
                    case "DeleteBlock": DeleteBlock((Guid)data[1]); break;
                    //case "GetGlobalConnectorEndpoints": result = GetGlobalConnectorEndpoints((string)data[1]); break;
                    //case "ProcessGlobalConnectorRequest": result = ProcessGlobalConnectorRequest((string)data[1], (object[])data[2]); break;
                    case "ReloadBlocks": ReloadBlocks(); break;
                    case "Disconnect": Disconnect((string)data[1]); break;
                    case "Dispose": Dispose(); return;
                    case "GetBlockWebMetaInfo": result = GetBlockWebMetaInfo((BlockWebMetaInfoType)data[1], (string)data[2]); break;
                    case "Connect": result = Connect((string)data[1], (int)data[2], (string)data[3]); break;
                    case "BlockHandles": result = BlockHandles; break;
                    case "BlockCount": result = BlockCount; break;
                    case "MigrateBlock":
                        {
                            //create given block and send migrate-done 
                            Guid guid = (Guid)data[0];
                            CID blockId = (CID)data[1];
                            object customData = data[2];

                            Guid response = addBlock(blockId, guid);
                            innerBlocks[response].OnAfterMigration(customData);

                            result = response;
                            break;
                        }
                }
            }
            catch (System.Exception exc)
            {
                logEvent(LogType.Exception, "Error Handling Call on Web Methods (" + methodName + "): " + exc.Message);
                throw;
            }

            sender.SendMessageAsync(msgCode, msgId, result);
        }

        #endregion

        #region IDisposable Members

        public virtual void Dispose()
        {
            if (peerManager != null)
            {
                peerManager.Disconnect();
                peerManager.Dispose();
                peerManager = null;
            }

            //also dispose all blocks
            foreach (IContainerBlock block in innerBlocks.Values)
            {
                block.Dispose();
            }
        }

        #endregion

        #region private methods
        private void intLogEvent(int type, string log)
        {
            logEvent((LogType)type, log);
        }

        private void logEvent(LogType type, string log)
        {
            this[EventCode.LogWebEvent].Raise(type, log);
        }
        #endregion

    }
}
